/**
 * @file lora_port_rtc.c
 * @brief RTC驱动适配
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2020-06-12
 * @copyright Copyright (c) 2020  烽火通信
 ***************************************************************
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version  <th>Author  <th>Description
 * <tr><td>2020-06-12 <td>1.0      <td>wangh   <td>内容
 * </table>
 */
#include <math.h>
#include <time.h>
#include "stm32f10x.h"
#include "lora_port_rtc.h"
#include "lora_port_timer.h"

#define LOG_LEVEL_		LOG_LVL_DEBUG
#include "bsp_log.h"

/*!
 * RTC Time base in ms
 */
#define RTC_ALARM_TICK_DURATION                     0.48828125      // 1 tick every 488us
#define RTC_ALARM_TICK_PER_MS                       2.048           // 1/2.048 = tick duration in ms



/*!
 * Flag used to indicates a the MCU has waken-up from an external IRQ
 */
volatile bool NonScheduledWakeUp = false;

/*!
 * \brief Flag to indicate if the timestamps until the next event is long enough
 * to set the MCU into low power mode
 */
static bool RtcTimerEventAllowsLowPower = false;

/*!
 * \brief Flag to disable the LowPower Mode even if the timestamps until the
 * next event is long enough to allow Low Power mode
 */
static bool LowPowerDisableDuringTask = false;

/*!
 * \brief Indicates if the RTC is already Initialized or not
 */
static bool RtcInitialized = false;

/*!
 * \brief Indicates if the RTC Wake Up Time is calibrated or not
 */
//static bool WakeUpTimeInitialized = false;

/*!
 * \brief Hold the Wake-up time duration in ms
 */
volatile uint32_t McuWakeUpTime = 0;

/*!
 * \brief Hold the cumulated error in micro-second to compensate the timing errors
 */
//static int32_t TimeoutValueError = 0;

/*!
 * Keep the value of the RTC timer when the RTC alarm is set
 */
static TimerTime_t RtcTimerContext = 0;


/*!
 * \brief RTC wakeup time computation
 */
static void RtcComputeWakeUpTime( void );

/*!
 * \brief Start the RTC Alarm (timeoutValue is in ms)
 */
static void RtcStartWakeUpAlarm( uint32_t timeoutValue );




void RtcInit( void )
{
    if( RtcInitialized == false )
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	// 使能PWR和BKP外设时钟
		PWR_BackupAccessCmd(ENABLE);	// 使能后备寄存器访问  
//		if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)		// 初次配置或者掉电复位
		{ 			
			BKP_DeInit();				// 复位备份区域 	
			
			RCC_LSEConfig(RCC_LSE_ON);	// 使能低速外部时钟 LSE
			
			/* 等待 LSE ready */
			while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
			{}
			
			RCC_RTCCLKConfig( RCC_RTCCLKSource_LSE );	
			RCC_RTCCLKCmd(ENABLE);
			RTC_WaitForSynchro();	// 等待RTC寄存器与APB1同步
			RTC_WaitForLastTask();						
			
			RTC_EnterConfigMode();				
			RTC_SetPrescaler(15);	// 16分频
			RTC_WaitForLastTask();
			RTC_ExitConfigMode();
			RTC_WaitForLastTask();
				
//			BKP_WriteBackupRegister(BKP_DR1, 0X5050);
		}
//		else	// 无需设置新时钟
		{
			// 检查是否掉电重启
			if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
				log_d("\r\nPower On Reset occurred...\r\n");
			else if (RCC_GetFlagStatus(RCC_FLAG_SFTRST) != RESET)
				log_d("\r\nSoft Reset occurred...\r\n");
			else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
				log_d("\r\nPin Reset occurred...\r\n");
			
			log_d("\r\nNo need to configure RTC...\r\n");
			
			RTC_WaitForSynchro();	//等待寄存器同步
		}
		
		
		NVIC_InitTypeDef NVIC_InitStructure;
		/* Enable the RTC Alarm Interrupt */
		NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init( &NVIC_InitStructure );

		/* Enable AlarmA interrupt */
		RTC_ITConfig( RTC_IT_ALR, DISABLE );
		RTC_WaitForLastTask();
		
		
        RtcInitialized = true;
    }
}

// 设置超时时间 ms
void RtcSetTimeout( uint32_t timeout )
{
    RtcStartWakeUpAlarm( timeout );
}

TimerTime_t RtcGetAdjustedTimeoutValue( uint32_t timeout )
{
//    if( timeout > McuWakeUpTime )
//    {   // we have waken up from a GPIO and we have lost "McuWakeUpTime" that we need to compensate on next event
//        if( NonScheduledWakeUp == true )
//        {
//            NonScheduledWakeUp = false;
//            timeout -= McuWakeUpTime;
//        }
//    }

//    if( timeout > McuWakeUpTime )
//    {   // we don't go in Low Power mode for delay below 50ms (needed for LEDs)
//        if( timeout < 50 ) // 50 ms
//        {
//            RtcTimerEventAllowsLowPower = false;
//        }
//        else
//        {
//            RtcTimerEventAllowsLowPower = true;
//            timeout -= McuWakeUpTime;
//        }
//    }
    return  timeout;
}

// 获取定时器当前时间 ms
TimerTime_t RtcGetTimerValue( void )
{
    double timeCounterTemp = 0.0;

    timeCounterTemp = ( double )RTC_GetCounter( ) * RTC_ALARM_TICK_DURATION;
	
	TimerTime_t timeCounter = round( timeCounterTemp );
	
    return ( timeCounter );
}


TimerTime_t RtcGetElapsedAlarmTime( void )
{
    TimerTime_t currentTime = 0;
    TimerTime_t contextTime = 0;

    currentTime = RtcGetTimerValue( );
    contextTime = round( ( double )RtcTimerContext * RTC_ALARM_TICK_DURATION );

    if( currentTime < contextTime )
    {
        return( currentTime + ( 0xFFFFFFFF - contextTime ) );
    }
    else
    {
        return( currentTime - contextTime );
    }
}

TimerTime_t RtcComputeFutureEventTime( TimerTime_t futureEventInTime )
{
    return( RtcGetTimerValue( ) + futureEventInTime );
}

TimerTime_t RtcComputeElapsedTime( TimerTime_t eventInTime )
{
    TimerTime_t elapsedTime = 0;

    // Needed at boot, cannot compute with 0 or elapsed time will be equal to current time
    if( eventInTime == 0 )
    {
        return 0;
    }

    elapsedTime = RtcGetTimerValue( );

    if( elapsedTime < eventInTime )
    { // roll over of the counter
        return( elapsedTime + ( 0xFFFFFFFF - eventInTime ) );
    }
    else
    {
        return( elapsedTime - eventInTime );
    }
}

void BlockLowPowerDuringTask ( bool status )
{
    if( status == true )
    {
        RtcRecoverMcuStatus( );
    }
    LowPowerDisableDuringTask = status;
}

void RtcEnterLowPowerStopMode( void )
{   
    if( ( LowPowerDisableDuringTask == false ) && ( RtcTimerEventAllowsLowPower == true ) )
    {   
//        // Disable IRQ while the MCU is being deinitialized to prevent race issues
//        __disable_irq( );
//    
//        BoardDeInitMcu( );
//    
//        __enable_irq( );
//    
//        /* Disable the Power Voltage Detector */
//        PWR_PVDCmd( DISABLE );

//        /* Set MCU in ULP (Ultra Low Power) */
//        PWR_UltraLowPowerCmd( ENABLE );

//        /*Disable fast wakeUp*/
//        PWR_FastWakeUpCmd( DISABLE );

//        /* Enter Stop Mode */
//        PWR_EnterSTOPMode( PWR_Regulator_LowPower, PWR_STOPEntry_WFI );
    }
}

void RtcRecoverMcuStatus( void )
{    
	
}

// 计算唤醒时间
static void RtcComputeWakeUpTime( void )
{
	McuWakeUpTime = 3;
}

// 设置告警时间 ms
static void RtcStartWakeUpAlarm( uint32_t timeoutValue )
{
	RtcTimerContext = RTC_GetCounter( );	// 记录起始计数值 tick
	
	uint32_t alarm_timeout = timeoutValue * RTC_ALARM_TICK_PER_MS + RtcTimerContext;
	
	RTC_SetAlarm(alarm_timeout);
	RTC_WaitForLastTask();	

    /* Wait for RTC APB registers synchronisation */
    RTC_WaitForSynchro( );
    
    /* Enable RTC Alarm A Interrupt */
    RTC_ITConfig( RTC_IT_ALR, ENABLE );
}




/*!
 * \brief RTC IRQ Handler on the RTC Alarm
 */
void RTC_Alarm_IRQHandler( void )
{
    if( RTC_GetITStatus( RTC_IT_ALR ) != RESET )
    {   
        RtcRecoverMcuStatus( );
		RtcComputeWakeUpTime( );
		BlockLowPowerDuringTask( false );
		
        TimerIrqHandler( );
    
        RTC_ClearITPendingBit( RTC_IT_ALR );
    }
}



/*********** (C) COPYRIGHT 2020 FiberHome *****END OF FILE****/



